package demo1;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.function.Function;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-08-16
 * Time: 15:01
 */
public class ReflectClassDemo {
    //怎么去使用反射呢，来修改Test中的name对象
    //第一步：先写一个方法来创建一个Class对象
    public static void reflectNewInstance1(){
        Class<?> classStudent = null;
        try {
            classStudent = Class.forName("demo1.Student");
            Student student = (Student) classStudent.newInstance();//newInstance也会抛出来异常(直接shift+alt+enter)，同时它的返回值是T,T被擦除成了object类

            System.out.println(student);
        }catch(ClassNotFoundException | InstantiationException | IllegalAccessException e){
            e.printStackTrace();
        }
    }

    public static void reflectNewInstance2(){
        Class<?> classStudent = null;
        try{
            //第一步：生成class对象
            classStudent = Class.forName("demo1.Student");

            //通过class对象来获得带有两个参数的构造方法，比不带参数的构造方法多了一步
            Constructor<?> constructor = classStudent.getDeclaredConstructor(String.class, int.class);//参数是你构造方法的类型

            //调用两个带参数的构造方法（private修饰的），安全性
            //调用setAccessible,反射打破了封装性，是一把双刃剑
            constructor.setAccessible(true);
            //第三步：通过这个对象来实例化带有两个参数的构造方法
            Student student1 = (Student)constructor.newInstance("xiaoming",5);
            //这个newInstance是constructor自己的方法，点进去，initargs 初始化的一个参数列表


            //是一个受查异常，也需要去添加，返回值也是一个object，需要强转
            System.out.println(student1);

        }catch (ClassNotFoundException e ){
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }

    }

    public static void reflectPrivateFeild(){
        Class<?> classStudent = null;
        try{
            classStudent = Class.forName("demo1.Student");
            //反射字段
            Field field = classStudent.getDeclaredField("name");//获取的这个字段是private私有的，得告诉编译器可以修改
            field.setAccessible(true);
            //通知放行
            Student student1 = (Student)classStudent.newInstance();//通过这个对象来实例化不带参数的构造方法
            field.set(student1,"caocao");//改字段
            System.out.println(student1);


        }catch (ClassNotFoundException e){
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    public static void reflectPrivateMethod(){
        Class<?> classStudent = null;
        try{
            //第一步：生成一个class对象
            classStudent = Class.forName("demo1.Student");
            //第二步：修改哪个方法(私有的就要让编译器放行)(返回类型是Method)
            Method method = classStudent.getDeclaredMethod("function",String.class);//(带参数的)
            method.setAccessible(true);
            //第三步：修改哪个对象的构造方法（前提那就先用class生成一个对象）(记得强转)
            Student student = (Student) classStudent.newInstance();
            method.invoke(student,"终于写完这个反射的带参数的方法了");//这里已经调用了function这个方法了，带参数的

        }catch(ClassNotFoundException e){
            e.printStackTrace();

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) {
        reflectNewInstance1();//调用方法（调用的Student中不带参数的构造方法 ）
        System.out.println("==============");
        reflectNewInstance2();
        System.out.println("==============");
        reflectPrivateFeild();
        System.out.println("==============");
        reflectPrivateMethod();
    }

}